﻿using System;
using System.Collections.Generic;

using TrivialPurfuit.Presentation.AskForCatagory;
using TrivialPurfuit.Business;

namespace TrivialPurfuit.Business
{
    /// <summary>
    /// This is where all the logic for the game belongs.
    /// </summary>
    public  class StateMachine
    {
        /// <summary>
        /// These states help with walking through the game. 
        /// Waiting to Get the Names and Catagories from the user. 
        /// Waiting for the user to Roll the Die. 
        /// Waiting for the group ask for the answer.
        /// </summary>
        // Asking the User or Group for the Catagory and Group Determine the P/F could be considered states because 
        // we are witing for the user, but I think these can be simple popups instead of actual states. It means less
        // to listen for and less changing the gameBoard question and annswer section around. We can add in the state
        // later if we don't like the popups.

        private enum GameState { RollTheDie, ChooseSpace, WaitToGiveAnswer, WaitForUserToVerifyAnswer };

        private GameState state;
        private GamePiece currentPlayerPiece;
        private List<int> highlightedDestinations;



        public void resetGame()
        {
            this.getNamesAndCategories();
            this.putPiecesInTheirStartingPositions();
            this.clearPlayersChips();
            this.hideQuestionAndAnswer();
            this.setFirstPlayer();
            this.enableOnlyDieButton();
            this.setStateToRollDie();
        }

        private void clearPlayersChips()
        {
            GameBoard.Instance.Piece1.clearChips();
            GameBoard.Instance.Piece2.clearChips();
            GameBoard.Instance.Piece3.clearChips();
            GameBoard.Instance.Piece4.clearChips();
        }

        public void userRolledTheDie()
        {
            if (this.state == GameState.RollTheDie)
            {
                this.setDieWithRandomNumber();
                this.highlightPossibleDestinations();
                this.disableAllButtons();
                this.hideQuestionAndAnswer();
                this.setStateToChooseSpace();
            }
        }

        public void userChoseASpace(int spaceNumber)
        {
            if (this.state == GameState.ChooseSpace && this.spaceIsAPossibleDestination(spaceNumber))
            {
                this.unhighlightDestinations();
                this.moveCurrentPlayersPieceToChosenSpace(spaceNumber);

                BoardMap.SpaceType spaceType = this.determineWhatKindOfSpaceWasLandedOn();

                if (spaceType == BoardMap.SpaceType.RollAgain)
                {
                    this.enableOnlyDieButton();
                    this.setStateToRollDie();
                }
                else
                {
                    this.setANewQuestionBySpaceType(spaceType);
                    this.displayQuestion();
                    this.enableOnlyAnswerButton();
                    this.setStateToWaitToGiveAnswer();
                }
            }
        }

        public void userRequestedTheAnswer()
        {
            if (this.state == GameState.WaitToGiveAnswer)
            {
                this.displayAnswer();
                this.enableOnlyVerifyButtons();
                this.setStateToWaitForUserToVerifyAnswer();
            }
        }

        public void userVerifiedTheAnswer(bool answerWasCorrect)
        {
            if (this.state == GameState.WaitForUserToVerifyAnswer)
            {
                if (answerWasCorrect)
                {
                    this.handleCorrectAnswer();
                }
                else
                {
                    this.setNextPlayer();
                    this.enableOnlyDieButton();
                    this.setStateToRollDie();
                }
            }
        }

        private void handleCorrectAnswer()
        {
            BoardMap.SpaceType spaceType = this.determineWhatKindOfSpaceWasLandedOn();

            if (spaceType == BoardMap.SpaceType.Normal)
            {
                this.enableOnlyDieButton();
                this.setStateToRollDie();
            }
            else if (spaceType == BoardMap.SpaceType.Base)
            {
                this.giveCategoryChipToCurrentPlayer();
                this.enableOnlyDieButton();
                this.setStateToRollDie();
            }
            else if (spaceType == BoardMap.SpaceType.Center && this.currentPlayerPiece.hasAllChips())
            {
                this.declareWinner();
                this.resetGame();
            }
            else if (spaceType == BoardMap.SpaceType.Center)
            {
                this.giveCategoryChipToCurrentPlayer();
                this.enableOnlyDieButton();
                this.setStateToRollDie();
            }
        }





        private void setStateToRollDie()
        {
            state = GameState.RollTheDie;
        }

        public void setStateToChooseSpace()
        {
            state = GameState.ChooseSpace;
        }

        private void setStateToWaitToGiveAnswer()
        {
            state = GameState.WaitToGiveAnswer;
        }

        private void setStateToWaitForUserToVerifyAnswer()
        {
            state = GameState.WaitForUserToVerifyAnswer;
        }

        private BoardMap.SpaceType determineWhatKindOfSpaceWasLandedOn()
        {
            int currentPlayersSpaceNumber = this.currentPlayerPiece.SpaceNumber;

            return BoardMap.determineSpaceTypeFromSpaceNumber(currentPlayersSpaceNumber);
        }

        private QuestionCategory determineWhatKindOfCategoryBySpaceType(BoardMap.SpaceType spaceType)
        {
            int spaceNumber = this.currentPlayerPiece.SpaceNumber;

            if (spaceType == BoardMap.SpaceType.Normal || spaceType == BoardMap.SpaceType.Base)
                return BoardMap.determineCategoryFromSpaceNumber(spaceNumber);

            else if (spaceType == BoardMap.SpaceType.Center && this.currentPlayerPiece.hasAllChips())
                return GetCategory.askForCategoryFromName("Group");

            else if (spaceType == BoardMap.SpaceType.Center)
                return GetCategory.askForCategoryFromName(this.currentPlayerPiece.PlayerName);

            else
                return null;
        }

        private QuestionCategory getCategoryFromSpace()
        {
            int spaceNumber = this.currentPlayerPiece.SpaceNumber;

            return GameBoard.Instance.Spaces[spaceNumber].Category;
        }

        private int determineCurrentPlayersIndex()
        {
            int result = 0;

            for (int index = 0; index < GameBoard.Instance.Pieces.Count; index++)
            {
                if (this.currentPlayerPiece == GameBoard.Instance.Pieces[index])
                    result = index;
            }

            return result;
        }

        private bool spaceIsAPossibleDestination(int spaceNumber)
        {
            return this.highlightedDestinations.Contains(spaceNumber);
        }

        public void highlightPossibleDestinations()
        {
            int dieValue = GameBoard.Instance.Die.Value;

            List<int> posibleDestinations = BoardMap.getPossibleDestinations(this.currentPlayerPiece, dieValue);
            highlightSpaces(posibleDestinations);
            this.state = GameState.ChooseSpace;
        }

        private void highlightSpaces(List<int> destinations)
        {
            if (highlightedDestinations != null)
                unhighlightDestinations();

            foreach (int spaceNumber in destinations)
                GameBoard.Instance.Spaces[spaceNumber].Highlight = true;

            highlightedDestinations = destinations;
        }

        private void unhighlightDestinations()
        {
            foreach (int spaceNumber in highlightedDestinations)
                GameBoard.Instance.Spaces[spaceNumber].Highlight = false;

            highlightedDestinations = null;
        }

        private void setDieWithRandomNumber()
        {
            GameBoard.Instance.Die = new Random().Next(1, 7);
        }

        private void enableOnlyDieButton()
        {
            GameBoard.Instance.EnableDieButton = true;
            GameBoard.Instance.EnableAnswerButton = false;
            GameBoard.Instance.EnableVerifyButtons = false;
        }

        private void enableOnlyAnswerButton()
        {
            GameBoard.Instance.EnableDieButton = false;
            GameBoard.Instance.EnableAnswerButton = true;
            GameBoard.Instance.EnableVerifyButtons = false;
        }

        private void enableOnlyVerifyButtons()
        {

            GameBoard.Instance.EnableDieButton = false;
            GameBoard.Instance.EnableAnswerButton = false;
            GameBoard.Instance.EnableVerifyButtons = true;
        }

        public void disableAllButtons()
        {
            GameBoard.Instance.EnableDieButton = false;
            GameBoard.Instance.EnableAnswerButton = false;
            GameBoard.Instance.EnableVerifyButtons = false;
        }

        private void setFirstPlayer()
        {
            if (GameBoard.Instance.Pieces.Count > 0)
            {
                this.currentPlayerPiece = GameBoard.Instance.Pieces[0];
                this.currentPlayerPiece.Highlight = true;
            }
        }

        private void setNextPlayer()
        {
            int nextPlayersIndex = determineCurrentPlayersIndex() + 1;

            if (nextPlayersIndex >= GameBoard.Instance.Pieces.Count)
                nextPlayersIndex = 0;

            this.currentPlayerPiece.Highlight = false;
            this.currentPlayerPiece = GameBoard.Instance.Pieces[nextPlayersIndex];
            this.currentPlayerPiece.Highlight = true;
        }

        private void putPiecesInTheirStartingPositions()
        {
            if (GameBoard.Instance.Piece1.PlayerName.Length > 0)
                GameBoard.Instance.Piece1.SpaceNumber = BoardMap.BASE1_SPACE_NUMBER;
            else 
                GameBoard.Instance.Piece1.SpaceNumber = BoardMap.NULL_SPACE_NUMBER;


            if (GameBoard.Instance.Piece2.PlayerName.Length > 0)
                GameBoard.Instance.Piece2.SpaceNumber = BoardMap.BASE2_SPACE_NUMBER;
            else
                GameBoard.Instance.Piece2.SpaceNumber = BoardMap.NULL_SPACE_NUMBER;


            if (GameBoard.Instance.Piece3.PlayerName.Length > 0)
                GameBoard.Instance.Piece3.SpaceNumber = BoardMap.BASE3_SPACE_NUMBER;
            else
                GameBoard.Instance.Piece3.SpaceNumber = BoardMap.NULL_SPACE_NUMBER;


            if (GameBoard.Instance.Piece4.PlayerName.Length > 0)
                GameBoard.Instance.Piece4.SpaceNumber = BoardMap.BASE4_SPACE_NUMBER;
            else
                GameBoard.Instance.Piece4.SpaceNumber = BoardMap.NULL_SPACE_NUMBER;
        }

        private void giveCategoryChipToCurrentPlayer()
        {
            int categoryID = GameBoard.Instance.QuestionCard.CategoryID;

            currentPlayerPiece.giveCategoryChip(categoryID);
        }

        private void declareWinner()
        {
            Presentation.Winner.Window1.ShowDialogNowWithWinnersName(this.currentPlayerPiece.PlayerName);
        }

        private void getNamesAndCategories()
        {
            Presentation.StartGame.StartGameView.ShowDialogNow();
        }

        private void moveCurrentPlayersPieceToChosenSpace(int spaceNumber)
        {
            this.currentPlayerPiece.SpaceNumber = spaceNumber;
        }

        private void setANewQuestionBySpaceType(BoardMap.SpaceType spaceType)
        {
            QuestionCategory category = this.determineWhatKindOfCategoryBySpaceType(spaceType);
            QuestionCard card = category.getRandomCard();

            GameBoard.Instance.QuestionCard = card;
        }

        private void displayQuestion()
        {
            GameBoard.Instance.ShowQuestion = true;
        }

        private void displayAnswer()
        {
            GameBoard.Instance.ShowAnswer = true;
        }

        public void hideQuestionAndAnswer()
        {
            GameBoard.Instance.ShowQuestion = false;
            GameBoard.Instance.ShowAnswer = false;
        }
    }
}
